home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
msysjour
/
vol05
/
05
/
parallel
/
par_poll.asm
< prev
next >
Wrap
Assembly Source File
|
1990-09-01
|
9KB
|
329 lines
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; PAR_POLL.ASM - Parallel Printer Port By Polling
;;;
;;;
;;; Copyright 1990 by Ross M. Greenberg
;;; for Microsoft Systems Journal
;;;
;;; This program demonstrates the ability to communicate between
;;; two PCs connected via the parallel printer port. In order for
;;; this program to work, a cable must be constructed that has the
;;; following pinouts:
;;;
;;; 1 ---------- 1- Common Ground
;;; 2 ---------- 15 \
;;; 3 ---------- 13 \
;;; 4 ---------- 12 > Data Out
;;; 5 ---------- 10 /
;;; 6 ---------- 11 /
;;; 10 ---------- 5 \
;;; 11 ---------- 6 \
;;; 12 ---------- 4 > Data In
;;; 13 ---------- 3 /
;;; 15 ---------- 2 /
;;;
;;; Run a copy of this program at each end of the cable.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Public Entry Points
public _psend, _prec, _pinit
DOSSEG
.MODEL small
.STACK 100h
FALSE equ 00h
TRUE equ 01h
FPTR equ 4
TIMEOUT equ -1
.DATA
;;no data
.CODE
real_port dw 0 ; the actual port used
timer dw 0 ; setup for timeout/dummy loop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; PINIT(PORT) - Initialize the port
;;;
;;; Port is zero based (first LPT is zero). First, find the actual
;;; base port to use and stuff it away in "real_port". Then, since
;;; we need an accurate representation of the speed of the machine,
;;; use the tick timer in INT 0x1a to see how fast the machine is
;;; for looping constants. Store that away in timer, and return the
;;; timing constant.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_pinit proc near
push bp
mov bp, sp
push bx
push cx
push dx
push si
push ds
mov ax, 40h ; printer ports are stored @ 40:8
mov ds, ax
mov bx, [bp + FPTR]
shl bx, 1
mov dx, word ptr 8[bx] ; get the base port, offset by port #
pop ds
mov cs:[real_port], dx ; store it
mov ah, 0 ; get the tick
int 01ah
mov si, dx
@@: mov ah, 0
int 01ah
cmp dx, si ; stay in loop until tick changes
jz @B
mov si, dx
xor bx, bx
cli ; accuracy means no ints!
@@: inc bx ; loop three times
mov cx, bx
loop $ ; one
mov cx, bx
loop $ ; two
mov cx, bx
loop $ ; three
mov ah, 0
int 01ah ; get the time
cmp dx, si ; changed?
jz @B ; nope. Increase the count
sti ; restart interrupts
mov cl, 9
shl bx, cl ; just make it a number of some sort
@@: mov cs:[timer], bx ; and save it
mov ax, bx ; and return with it in ax
pop si
pop dx
pop cx
pop bx
pop bp
ret
_pinit endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; PSEND(STRING_PTR, LEN)
;;;
;;; Calls the send_char routine with character to send in al for LEN
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_psend proc near
push bp
mov bp, sp
push bx
push cx
push dx
mov dx, cs:[real_port] ; base port
mov bx, [bp + FPTR] ; send buffer
mov cx, [bp + FPTR + 2] ; count
xor bp, bp ; zero out counter
jcxz _psend_ret ; if empty, go home
_psend_lp:
mov al, [bx] ; get the character
call send_char ; and send it
jnc _psend_ret ; if it didn't send, go home
inc bx ; increment the pointer
inc bp ; and the counter
loop _psend_lp ; do it again
_psend_ret:
pop dx
pop cx
pop bx
mov ax, bp ; move counter into ax
pop bp
ret ; go home
_psend endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; PREC(STRING_PTR, LEN)
;;;
;;; Fetch LEN characters and stuff them into STRING_PTR.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_prec proc near
push bp
mov bp, sp
push bx
push cx
push dx
mov bx, [bp + FPTR] ; receive buffer
mov cx, [bp + FPTR + 2] ; count
mov dx, cs:[real_port] ; the base port
xor bp, bp ; zero cnt
jcxz _prec_ret ; no count, no probs
_prec_lp:
call get_char ; get a character
jnc bad_rec ; whoops! set for short cnt
mov [bx], al ; save the character
inc bx ; bump the pointer
inc bp ; and the counter
loop _prec_lp ; as often as you have to
jmp _prec_ret
bad_rec:
or bp, 08000h ; set the short cnt indicator
_prec_ret:
pop dx
pop cx
pop bx
mov ax, bp ; move the count in
pop bp
ret
_prec endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; send-char - sends character in al
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
send_char proc near
push cx
mov cx, cs:[timer] ; get the timing constant
mov ah, al ; save the character
inc dx ; bump up to the control port
in al, dx ; read it
shl al, 1 ; pop it left
jc go_home ; hi bit set? Remember it's backwards
dec dx ; back to the base port
mov al, ah ; get the character back
shr al,1
shr al,1
shr al,1
shr al,1
and al,0Fh ; hi nybble first, anded just for that
out dx, al ; output the nybble
inc dx ; back up to control port
@@: in al, dx ; get data
shl al, 1 ; hi bit set to go?
jc @F ; yes
loop @B ; no, loop until timeout
jmp go_home ; timed out. Bomb out.
@@: dec dx ; back to data port
mov al, ah ; get the character back
or al, 10h ; set the hi bit (its backwards!)
out dx, al ; output the character
inc dx ; and back to control
mov cx, cs:[timer] ; get the timing constant
@@: in al, dx ; and wait for ACK
shl al, 1
jnc go_home ; done
loop @B ; looks like an error?
go_home:
dec dx ; mark it as ready and willing
mov al, 10h
out dx, al
xor ah, ah
stc
pop cx
ret
send_char endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; get-char - retrieves character into al
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_char proc near
push cx
mov cx, cs:[timer] ; get looping constant
inc dx ; upto control port
@@: in al, dx ; we shall do no port before its time
shl al, 1 ; remember its reversed
mov ah, al ; save it unshifted
jc @F ; so carry means go ahead
loop @B ; still set, try again
clc ; carry clear means no good
pop cx
ret ; go home
@@: and ah,0F0h ; only the high nybble
dec dx ; back to data port
mov al, 0 ; ACK the nybble
out dx, al
inc dx ; back to control
mov cx, cs:[timer] ; get looping constant
@@: in al, dx ; wait for it
shl al, 1
jnc @F
loop @B
dec dx ; no go. Clean up a tad.
mov al, 10h ; set the flag
out dx, al ; output it on the data port
clc
pop cx
ret
@@: in al, dx ; get the next nybble
shr al, 1 ; normalize it
shr al, 1
shr al, 1
and al, 0Fh ; strip off the naughty bits
or ah, al ; create a character in ah
dec dx ; ack the byte
mov al, 10h ; set the flag
out dx, al ; output it
mov al, ah ; retreive the character
stc
pop cx
ret
get_char endp
end